package com.easylinkin.linkappapi.blockqueue;

import cn.hutool.core.date.DateUtil;
import com.easylinkin.bases.redis.util.RedisUtil;
import com.easylinkin.linkappapi.blockqueue.constant.QueueKeyConstant.QueueKeyEnum;
import com.easylinkin.linkappapi.blockqueue.vo.BlockingQueueUseVO;
import com.easylinkin.linkappapi.blockqueue.vo.BusinessDayUserVO;
import com.easylinkin.linkappapi.openapi.dto.DatapushDTO;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


/**
 * @author xiaoyang
 * @version 1.0
 * @date 2023/08/14
 * @description 队列管理器
 */
@Service
@Slf4j
public class QueueManager {
  private final ConcurrentMap<String, BlockingQueue<DatapushDTO>> queues = new ConcurrentHashMap<>();

  @Resource
  private final RedisTemplate<String, DatapushDTO> redisTemplate = new RedisTemplate<>();

  @Value("${datapush.useRedis:true}")
  private boolean useRedis;

  @Value("${datapush.maxQueueNum:4000}")
  private int maxQueueNum;

  @Resource
  private RedisUtil redisUtil;

  @PostConstruct
  public void init() {
    //  QueueKeyConstant 动态获取 并创建 队列
    List<String> allQueueKey = QueueKeyEnum.getAllQueueKey();
    for (String queueKey : allQueueKey) {
      createQueue(queueKey, useRedis);
    }
  }

  private void createQueue(String queueName, boolean useRedis) {
    BlockingQueue<DatapushDTO> queue;
    if (useRedis) {
      queue = new RedisBlockingQueue<>(redisTemplate,queueName);
    } else {
      queue = new MemoryBlockingQueue<>();
    }
    queues.put(queueName, queue);
  }

  public BlockingQueue<DatapushDTO> getQueue(String queueName) {
    return queues.get(queueName);
  }

  public void enqueue(String queueName, DatapushDTO item) {
    BlockingQueue<DatapushDTO> queue = queues.get(queueName);
    if (queue != null) {
      if (queue.size() >= maxQueueNum) {
        log.error("{} size is max, queue size is {}", queueName ,queue.size());
        return;
      }
      queue.add(item);
    }
  }

  public DatapushDTO dequeue(String queueName) throws InterruptedException {
    BlockingQueue<DatapushDTO> queue = queues.get(queueName);
    if (queue != null) {
      return queue.take();
    }
    return null;
  }

  public int getQueueSize(String queueName) {
    BlockingQueue<DatapushDTO> queue = queues.get(queueName);
    if (queue != null) {
      return queue.size();
    }
    return 0;
  }

  public List<BlockingQueueUseVO> getPendingTasksPerQueue() {
    // 查询所有队列的长度 和 执行次数 和 耗时 信息
    List<BlockingQueueUseVO> blockingQueueUseVOS = new ArrayList<>();

    // 获取近三天
    List<String> days = currentThreeDays();

    for (Map.Entry<String, BlockingQueue<DatapushDTO>> entry : queues.entrySet()) {
      List<BusinessDayUserVO> threeDays = new ArrayList<>();
      String queueKey = entry.getKey();
      BlockingQueueUseVO blockingQueueUseVO = new BlockingQueueUseVO();
      blockingQueueUseVO.setQueueKey(queueKey);
      // 查询redis 最近使用情况
      for (String day : days) {
        String queueKeySuccess = "comsumerQueue:" + queueKey + ":success:" + day;
        String queueKeyTime = "comsumerQueue:" + queueKey + ":time:" + day;
        BusinessDayUserVO businessDayUserVO = new BusinessDayUserVO();
        businessDayUserVO.setSuccess(redisUtil.get(queueKeySuccess) == null ? 0 : Integer.parseInt(redisUtil.get(queueKeySuccess).toString()));
        businessDayUserVO.setTime(redisUtil.get(queueKeyTime) == null ? 0 : Integer.parseInt(redisUtil.get(queueKeyTime).toString()));
        businessDayUserVO.setDay(day);
        threeDays.add(businessDayUserVO);
      }
      blockingQueueUseVO.setBusinessDayUserVOList(threeDays);
      blockingQueueUseVO.setSize(entry.getValue().size());
      blockingQueueUseVOS.add(blockingQueueUseVO);
    }
    return blockingQueueUseVOS;
  }

  private List<String> currentThreeDays() {
    List<String> days = new ArrayList<>();
    days.add(DateUtil.format(new Date(), "yyyyMMdd"));
    days.add(DateUtil.format(DateUtil.yesterday(), "yyyyMMdd"));
    days.add(DateUtil.format(DateUtil.offsetDay(new Date(),-2), "yyyyMMdd"));
    return days;
  }

  public Map<String, List<Object>> getCircuitBreakerUrlList() {
    Map<String, List<Object>> map = new HashMap<>();
    // 获取近三天
    List<String> days = currentThreeDays();
    // 查询redis 最近使用情况
    for (String day : days) {
      String circuitBreakerKey = "circuitBreaker:" + day;
      List<Object> objects = redisUtil.lGet(circuitBreakerKey,0,-1);
      map.put(day, objects);
    }
    return map;
  }
}
